##############################################################################
#
# Linux.pm 
# ========
#
# Author: Steven Liang <stliang@gmail.com>
#
# Purpose:
#   Parent class of Linux types
#   Linux.pm is a child of Node.
#
# Assumptions:
#   1.) 
#
# Supported methods:
#   All Node's methods plus
#   new($ip, $userName, $passWord ; $port || 23);
#   su($superUserPassword, $passWordPrompt, $cmdPrompt);
#   kill($processIDString);
#   getPortName($IP);
#   setMTU($IP; $mtuSize || 1500);
#
# Note:
#   Variable after ";" is optional variable and value after "||" is 
#   default value
#
##############################################################################

package Linux;
$VERSION = 1.00;

@ISA = qw(Node); # The @ISA array supports multiple inheritance
		 # For single parent use "use base" key word.

use strict;
use AutoTest::Exceptions;

# Constructor: new
# Purpose:     Instantiate a Linux object
# Parameters:
#       1.) ip : IP address of the node
#       2.) userName : User name used for login
#       3.) passWord : Password used for login
#       4.) port : A port to use for telnet, default value is 23
#
# Returns:    An instance of Network::Linux class
#
sub new ($$$;$) {
	my $class = shift;
	my $self = { };
	if (defined($_[3])) {
		$self = Node->new($_[0], $_[1], $_[2], $_[3]);
	} else {
		$self = Node->new($_[0], $_[1], $_[2]);
	}
	bless $self, $class;
	return $self;
}

# Method:     su
# Purpose:    Switch to super user mode
# Parameters:
#       1.) superUserPassword : The super user password of this Linux
#       2.) passWordPrompt : The password prompt expected after su
#       3.) cmdPrompt : The command prompt expected after successful su
#
# Returns:    Void
sub su ($$$) {
        my ($self) = shift;
        my ($superUserPassword) = shift;
        my ($passWordPrompt) = shift;
        my ($cmdPrompt) = shift;
	$self->cmdPrompt($cmdPrompt);
        $self->{exp}->send("su\r");
	$self->{exp}->expect($self->expectTimeout(), '-re', $passWordPrompt) or 
		AutoTest::Exception::Expect->throw("timeout expecting password prompt");
        $self->{exp}->send("$superUserPassword\r");
	$self->{exp}->expect($self->expectTimeout(), '-re', $cmdPrompt) or 
		AutoTest::Exception::Expect->throw("timeout expecting command prompt");
}

# Method:     kill
# Purpose:    To kill a process
# Parameters:
#       1.) processIDString : The string that identifies the process from "ps"
#				command output
#
# Returns:    
#	1 if kill successed
#	0 if kill failed
sub kill ($) {
        my ($self) = shift;
        my ($processIDString) = shift;
	my $processNotRunning = 1;
	my $processID = "";
	my $cmdPrompt = $self->cmdPrompt();
        $self->{exp}->send("ps -aux | grep \"$processIDString\"\r");
        $self->{exp}->expect($self->expectTimeout(), '-re', $cmdPrompt) or
                AutoTest::Exception::Expect->throw("timeout expecting command prompt");
	my $processes = $self->{exp}->before();
	# Parse the command output and extra out the default route info
	my @lines = split ( /\n/, $processes);
	my $line = "";
	foreach $line (@lines) {
		if ($line =~ /.*     ([0-9]+)  .*\d+:\d+ $processIDString/) {
			$processID = $1;
			$processNotRunning = 0;
			last;
		}
	}
	if (!$processNotRunning) {
                $self->{exp}->send("kill -9 $processID\r");
		$self->{exp}->expect($self->expectTimeout(), '-re', $cmdPrompt) or
                AutoTest::Exception::Expect->throw("timeout expecting command prompt");
        }
	return $processNotRunning
}

# Method:     getPortName
# Purpose:    Find the network port name that is associated with given IP
# Parameters:
#       1.) IP : The interested IP address
# Returns:
#       The Ethernet port name
sub getPortName ($) {
        my ($self) = shift;
        my ($IP) = shift;
        my $currentPort = "";
        my $found = 0;
        my $cmdPrompt = $self->cmdPrompt();
        $self->{exp}->send("ifconfig\r");
        $self->{exp}->expect($self->expectTimeout(), '-re', $cmdPrompt) or
                AutoTest::Exception::Expect->throw("timeout expecting command prompt");
        my $ports = $self->{exp}->before();
        my @lines = split ( /\n/, $ports);
        my $line = "";
        foreach $line (@lines) {
		if ($line =~ /eth\d+/) {
			$line =~ /(eth\d+)/;
			$currentPort = $1;
		}
                if ($line =~ /$IP/) {
                        $found = 1;
                        last;
                }
        }

        if ($found) {
        	return $currentPort
        } else {
        	return ""
	}
}


# Method:     setMTU
# Purpose:    Sett he Max Transmit Unit (MTU) of a network interface
# Parameters:
#       1.) IP 	: The IP address of the interested network interface
#       2.) mtuSize : The MTU size to set
# Returns:
#       void
sub setMTU ($;$) {
        my ($self) = shift;
        my ($IP) = shift;
        my ($mtuSize) = defined($_[0]) ? shift : 1500;
        my $foundMTU = 0;
        my $foundEth = 0;
        my $cmdPrompt = $self->cmdPrompt();
	my $ethn = $self->getPortName($IP);

	if ($ethn eq "") {
                AutoTest::Exception->throw("Unable to get the network port name from the IP given");
	}
 
        $self->{exp}->send("/sbin/ifconfig $ethn mtu $mtuSize up\r");
        $self->{exp}->expect($self->expectTimeout(), '-re', $cmdPrompt) or
                AutoTest::Exception::Expect->throw("timeout expecting command prompt");
        $self->{exp}->send("/sbin/ifconfig -a\r");
        $self->{exp}->expect($self->expectTimeout(), '-re', $cmdPrompt) or
                AutoTest::Exception::Expect->throw("timeout expecting command prompt");
        my $portsInfo = $self->{exp}->before();
        my @lines = split ( /\n/, $portsInfo);
        my $line = "";
        foreach $line (@lines) {
                if ($line =~ /$ethn/) {
                        $foundEth = 1;
                }
		if ($foundEth) {
			if ($line =~ /$mtuSize/) {
				$foundMTU = 1;
				last;
			}
		}
	}
	if (!$foundMTU) {
                AutoTest::Exception->throw("Failed to set MTU");
	}
}
